<template>
	<div class="home" ref="home" :style="{ background }">
		<my-header />
		<div
			class="messageList"
			ref="messageList"
			@scroll="handleScroll"
			@mouseenter="handleEnter"
			@mouseleave="handleLeave"
		>
			<message-list v-for="msg in messages" :key="msg.id" :data="msg" />
		</div>
		<div
			class="to-bottom"
			:class="{ 'is-hidden': isBottom }"
			title="到底部"
			@click="toBottom"
		>
			<span v-if="unreadMessages !== 0" class="unreadMessages">{{
				unreadMessages
			}}</span>
			<i class="el-icon-message-solid" v-else></i>
		</div>
		<send-msg />
	</div>
</template>

<script>
import { encode, decode } from "../utils/bilibili-live-wsData";
import { nanoid } from "nanoid";
import { mapState, mapMutations, mapActions } from "vuex";
export default {
	data() {
		return {
			// 直播姬窗口背景颜色
			background: ` rgba(0, 0, 0, ${localStorage.getItem("liveOpacity") /
				100 || 0.7})`,
			// webSocket请求
			websocket: "",
			// 房间id
			roomid: "",
			// 定时器
			timer: null,
			// 被淹没的消息总数
			unreadMessages: 0,
			// 是否在最底部
			isBottom: true,
			// 语音播报
			voiceBroadcast: new Audio(),
			// 触发音效
			soundEffect: new Audio(),
			// 自动回复
			autoReplyTimer: null,
		};
	},
	mounted() {
		// 等待接收其它窗口通信透明度
		this.$electron.remote.ipcMain.on("setOpacity", (e, val) => {
			this.$refs.home.style.background = `rgba(0, 0, 0, ${val / 100})`;
		});
		// 等待接收其它窗口通信透明度
		this.$electron.remote.ipcMain.on("setRoomId", (e, val) => {
			this.roomid = val;
			this.webSocket();
			this.clearMessages(null);
		});

		// 监听百度语音播报
		this.voiceBroadcast.addEventListener("ended", () => {
			this.nextVoice();
		});

		this.$electron.remote.ipcMain.on(
			"appendAutoReply",
			(e, { uname, message }) => {
				this.automaticReplyFun(uname, message, true);
			}
		);
	},
	methods: {
		// 引入vuex事件
		...mapMutations([
			"appendMessage",
			"clearMessages",
			"appendVoices",
			"nextVoice",
			"appendAutoReply",
			"nextAutoReply",
		]),
		...mapActions(["sendMsg"]),

		// webSocket请求
		webSocket() {
			// 事先存在ws请求 先关闭
			if (this.websocket) {
				this.websocket.close();
			}
			// 先清除定时器
			if (this.timer) {
				clearInterval(this.timer);
				this.timer = null;
			}
			// 开启新的ws连接
			this.websocket = new WebSocket(
				"ws://broadcastlv.chat.bilibili.com:2244/sub"
			);
			// 打开ws链接
			this.websocket.onopen = () => {
				// 发送参数
				this.websocket.send(
					encode(
						JSON.stringify({
							protover: 1,
							clientver: "1.4.0",
							roomid: this.roomid,
						}),
						7
					)
				);
				this.websocket.send(encode("", 2));
				this.websocket.onmessage = async (msgEvent) => {
					const packet = await decode(msgEvent.data);
					switch (packet.op) {
						// 首次进入
						case 8:
							// console.log('首次进入');
							break;
						case 3:
							// 给header进程发送事件
							this.$electron.ipcRenderer.send(
								"setPopular",
								packet.body.count
							);
							break;
						case 5:
							packet.body.forEach((body, i) => {
								// 给每条设置随机一个id, 防止消息重复
								body.id = nanoid();
								// 设置一个当前时间
								body.time = Date.now();
								// 进入直播间
								body.isEnter =
									body.cmd === "INTERACT_WORD" &&
									body.data.msg_type === 1;
								switch (body.cmd) {
									// 接收到弹幕
									case "DANMU_MSG":
										// 点歌等处理
										this.handleDanmuMsg(body);
										break;
									// 接收到单个礼物
									case "SEND_GIFT":
										this.appendVoices({
											message: `感谢${body.data.uname}${
												body.data.action
											}${body.data.num ||
												body.data.combo_num}个${body
												.data.giftName ||
												body.data.gift_name}`,
										});
										break;
									// 接收到组合礼物(除辣条)
									case "COMBO_SEND":
										// 读礼物弹幕
										this.appendVoices({
											message: `感谢${body.data.uname}${
												body.data.action
											}${body.data.num ||
												body.data.combo_num}个${body
												.data.giftName ||
												body.data.gift_name}`,
										});
										break;
									// 进入直播间(包括进入直播间和关注分享)
									case "INTERACT_WORD":
										if (body.data.msg_type === 2) {
											this.appendVoices({
												message: `感谢${body.data.uname}的关注`,
											});
										}
										if (body.data.msg_type === 3) {
											this.appendVoices({
												message: `感谢${body.data.uname}分享直播间`,
											});
										}
										if (body.data.msg_type > 3) {
											console.error(
												"body.data.msg_type > 3",
												body.data
											);
										}
										break;
									//   case 'WELCOME':
									//     console.log(`欢迎 ${body.data.uname}`);
									//     break;
									//     // 此处省略很多其他通知类型
									//   case "INTERACT_WORD":
									//     console.log(`%c[+] 欢迎 [${body.data.fans_medal.medal_name} ${body.data.fans_medal.medal_level}]${body.data.uname}`, 'color:#ccc;');
									//     break;
									default:
									// console.log("5++++ body ->", body);
								}
								// 判断是否在底部 加信息条数
								this.handleMessageTotal(body);
								this.appendMessage(body);
							});
							break;
						default:
						// console.log("6++++" + packet);
					}
					// 信息溢出滚动条自行滚动
					let list = this.$refs.messageList;
					this.$nextTick(() => {
						if (this.isBottom) {
							list.scrollTop = list.scrollHeight;
						}
					});
				};
			};
			this.websocket.onerror = (err) => {
				this.websocket && this.websocket.close();
				clearInterval(this.timer);
				this.timer = null;
				this.websocket = null;
				this.webSocket();
			};
			this.websocket.onclose = (err) => {
				clearInterval(this.timer);
				this.timer = null;
				this.websocket = null;
				this.webSocket();
			};
			// 保持ws一直处于链接状态
			this.timer = setInterval(() => {
				this.websocket.send(encode("", 2));
			}, 30000);
		},

		// 不在底部,每次新增一条信息+1
		handleMessageTotal() {
			if (!this.isBottom) {
				this.unreadMessages++;
			}
		},

		// 处理接收到的信息
		handleDanmuMsg(body) {
			// 获取信息, 发送者, 发送者uid
			let [message, uname, uid] = [
				body.info[1],
				body.info[2][1],
				body.info[2][0],
			];
			// 点歌操作
			if (/^点歌/.test(message)) {
				message = message.replace(/^点歌/, "");
				if (!message.trim()) {
					this.sendMsg({
						message: `自动回复${uname.slice(0, 15)}：`,
						automaticReply: true,
					});
					setTimeout(() => {
						this.sendMsg({
							message: "歌曲名称不能为空！",
							automaticReply: true,
						});
					}, 1500);
				} else {
					this.$electron.ipcRenderer.send("addMusic", {
						uname,
						val: message.trim(),
					});
				}
			} else if (/^切歌$/.test(message)) {
				this.$electron.ipcRenderer.send("switchMusic", uname);
				// 切歌操作
			} else {
				// 加入语音播报
				this.appendVoices({
					message,
				});
				// 判断是否触发音效关键字
				const soundEffentList = JSON.parse(
					localStorage.getItem("soundEffectKeywordsList") || "[]"
				);
				soundEffentList.forEach((item) => {
					const soundEffentReg = new RegExp(
						item.keyword.join("|"),
						"i"
					);
					if (soundEffentReg.test(message)) {
						this.soundEffect.src = `https://www.ayangweb.cn/audio/${item.content}`;
						this.soundEffect.play();
					}
				});

				// 判断是否触发自动回复
				if (
					uid != localStorage.getItem("liveUid") &&
					uid != localStorage.getItem("robotId")
				) {
					this.automaticReplyFun(uname, message);
				} else {
					if (
						uid == localStorage.getItem("liveUid") &&
						!+localStorage.getItem("ignoreUpReply")
					) {
						this.automaticReplyFun(
							localStorage.getItem("upUname"),
							message
						);
					}
					if (
						uid == localStorage.getItem("robotId") &&
						!!+localStorage.getItem("openRobot") &&
						!+localStorage.getItem("ignoreRobotReply")
					) {
						this.automaticReplyFun(
							localStorage.getItem("robotUname"),
							message
						);
					}
				}
			}
		},

		// 滚动条滚动事件
		handleScroll(e) {
			const { scrollTop, scrollHeight, clientHeight } = e.target;
			if (scrollTop < scrollHeight - clientHeight) {
				this.isBottom = false;
			} else {
				this.isBottom = true;
				this.unreadMessages = 0;
			}
		},

		// 去底部
		toBottom() {
			const list = this.$refs.messageList;
			list.scrollTop = list.scrollHeight;
		},

		// 语音播报
		playVoiceBroadcast() {
			if (this.currentVoice) {
				// 谷歌语音播报
				if (
					localStorage.getItem("voiceBroadcastType") &&
					localStorage.getItem("voiceBroadcastType") == "Google"
				) {
					var msg = new SpeechSynthesisUtterance(
						this.currentVoice.message
					);
					speechSynthesis.speak(msg);
					this.nextVoice();
				} else {
					// 百度语音播报
					const url =
						"http://tts.baidu.com/text2audio?lan=zh&ie=UTF-8&text=" +
						encodeURI(this.currentVoice.message);
					this.voiceBroadcast.src = url;
					this.voiceBroadcast.play();
				}
			}
		},

		// 鼠标移入决定是否穿透
		handleEnter() {
			if (!!+localStorage.getItem("livePenetrate")) {
				this.$electron.ipcRenderer.send("window-penetrate", true, {
					forward: true,
				});
			}
		},

		// 鼠标移出取消穿透
		handleLeave() {
			this.$electron.ipcRenderer.send("window-penetrate", false);
		},

		// 自动回复方法
		automaticReplyFun(uname, message, appoint) {
			if (appoint) {
				this.appendAutoReply({
					message: `自动回复${uname.slice(0, 5)}：${message}`,
					automaticReply: true,
				});
			} else {
				const automaticReplyList = JSON.parse(
					localStorage.getItem("automaticReplyKeywordsList") || "[]"
				);
				automaticReplyList.forEach((item) => {
					const automaticReplyReg = new RegExp(
						item.keyword.join("|", "i")
					);
					if (automaticReplyReg.test(message)) {
						this.appendAutoReply({
							message: `自动回复${uname.slice(0, 5)}：${
								item.content
							}`,
							automaticReply: true,
						});
					}
				});
			}
		},
	},
	computed: {
		...mapState([
			"messages",
			"currentVoice",
			"currentautoReply",
			"autoReplyList",
		]),
	},
	watch: {
		currentVoice(newVal) {
			this.playVoiceBroadcast();
		},

		currentautoReply(newVal) {
			if (newVal) {
				this.autoReplyTimer = setTimeout(() => {
					this.sendMsg(newVal);
				}, 1500);
			}
		},
	},
};
</script>

<style lang="scss">
.home {
	height: 100vh;
	color: #fff;
	.messageList {
		overflow: auto;
		height: calc(100vh - 69.5px);
		padding: 10px;
		-webkit-app-region: no-drag;
		scroll-behavior: smooth;
		&::-webkit-scrollbar {
			width: 10px;
		}
		&::-webkit-scrollbar-thumb {
			border-radius: 5px;
			background-color: rgba(255, 255, 255, 0.1);
		}
		&::-webkit-scrollbar-track {
			background-color: transparent;
		}
	}
	.to-bottom {
		position: fixed;
		bottom: 30px;
		right: 20px;
		display: flex;
		justify-content: center;
		align-items: center;
		width: 24px;
		height: 24px;
		background-color: #3478be;
		border-radius: 8px;
		border-bottom-right-radius: 0;
		transform: scale(1);
		transform-origin: right bottom;
		transition: all 0.3s;
		cursor: pointer;
		.unreadMessages {
			font-size: 14px;
		}
		i {
			font-size: 16px;
		}
		&.is-hidden {
			transform: scale(0);
		}
	}
}
</style>
